package com.xstudio.pvzreborn.entity;

import com.xstudio.pvzreborn.PVZReborn;
import com.xstudio.pvzreborn.entity.entities.PVZLivingEntityBase;
import com.xstudio.pvzreborn.entity.entities.misc.EntitySunshine;
import com.xstudio.pvzreborn.entity.entities.plant.EntityPlantWallNut;
import com.xstudio.pvzreborn.event.ClientEventListener;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.RangedAttribute;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * @author Bread_NiceCat
 */
public class EntityManager {

	private static final Map<String, RegistryObject<EntityType<?>>> ENTITIES = new HashMap<>();
	private static final Map<RegistryObject<EntityType<? extends Entity>>, Supplier<Builder>> ATTRIBUTES = new HashMap<>();
	private static final DeferredRegister<EntityType<?>> ENTITY_REGISTER = DeferredRegister.create(ForgeRegistries.ENTITIES, PVZReborn.MOD_ID);

	public static void init(IEventBus bus) {
		PVZReborn.LOGGER.info("Initializing entities");
		ENTITY_REGISTER.register(bus);
		resolveAttribute();
		register();
		PVZReborn.LOGGER.info("Initialized entities");
	}

	public static <T extends PVZLivingEntityBase> void registerLivingEntity(@NotNull EntityRegisterHelper<T> builder, @NotNull Supplier<AttributeSupplier.Builder> attribute) {
		ATTRIBUTES.put(registerEntity(builder), attribute);
	}

    public static <T extends Entity> RegistryObject<EntityType<? extends Entity>> registerEntity(@NotNull EntityRegisterHelper<T> builder) {
        RegistryObject<EntityType<? extends Entity>> entity = ENTITY_REGISTER.register(builder.getName(), builder.build());
        ENTITIES.put(builder.getName(), entity);
        return entity;
    }

	public static Map<RegistryObject<EntityType<? extends Entity>>, Supplier<Builder>> getAttribute() {
		return ATTRIBUTES;
	}

	@NotNull
	@SuppressWarnings("unchecked")
	public static <T extends Entity> EntityType<T> getEntity(String name) {
		return (EntityType<T>) Objects.requireNonNull(ENTITIES.get(name), "Unable to load entity:" + name).get();
	}

	/**
	 * 如何正确注册实体:
	 * <p>
	 * 1.在这个方法里面注册实体
	 * <p>
	 * 2.在{@link ClientEventListener#onRegisterRenderer}和{@link com.xstudio.pvzreborn.event.ClientEventListener#onRegisterLayers}
	 * 中注册渲染器和图层
	 */
	private static void register() {
		registerLivingEntity(EntityRegisterHelper.base(EntityPlantWallNut.NAME, EntityPlantWallNut::new, MobCategory.MISC).sized(1f, 1f), EntityPlantWallNut::attribute);
		registerEntity(EntityRegisterHelper.base(EntitySunshine.NAME, EntitySunshine::new, MobCategory.MISC));
	}

	private static void resolveAttribute() {
		((RangedAttribute) Attributes.MAX_HEALTH).maxValue = Double.MAX_VALUE;
	}

	/**
	 * @author Bread_NiceCat
	 */
	public static class EntityRegisterHelper<T extends Entity> {

		private final EntityType.Builder<T> builder;
		private final ResourceLocation name;

		public EntityRegisterHelper(String name, EntityType.EntityFactory<T> factory, MobCategory category) {
			this.builder = EntityType.Builder.of(factory, category);
			this.name = PVZReborn.prefix(name);
		}

		@NotNull
		public static <T extends Entity> EntityRegisterHelper<T> base(String name, EntityType.EntityFactory<T> pFactory, MobCategory pCategory) {
			return new EntityRegisterHelper<>(name, pFactory, pCategory);
		}

		public EntityRegisterHelper<T> sized(float weigh, float height) {
			builder.sized(weigh, height);
			return this;
		}

		public Supplier<EntityType<T>> build() {
			return () -> builder.build(name.toString());
		}

		public String getName() {
			return name.getPath();
		}

	}

}
